home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / random < prev    next >
Text File  |  1991-04-05  |  42KB  |  1,240 lines

  1. /*
  2.  * This file contains the command processing functions for a number of random
  3.  * commands. There is no functional grouping here, for sure.
  4.  */
  5.  
  6. #include        <stdio.h>
  7. #include        "estruct.h"
  8. #include        "etype.h"
  9. #include        "edef.h"
  10. #include        "elang.h"
  11.  
  12. /*
  13.  * Set fill column to n.
  14.  */
  15. PASCAL NEAR setfillcol(f, n)
  16. {
  17.         fillcol = n;
  18.         mlwrite(TEXT59,n);
  19. /*              "[Fill column is %d]" */
  20.         return(TRUE);
  21. }
  22.  
  23. /*
  24.  * Display the current position of the cursor, in origin 1 X-Y coordinates,
  25.  * the character that is under the cursor (in hex), and the fraction of the
  26.  * text that is before the cursor. The displayed column is not the current
  27.  * column, but the column that would be used on an infinite width display.
  28.  * Normally this is bound to "C-X =".
  29.  */
  30. PASCAL NEAR showcpos(f, n)
  31. {
  32.         register LINE   *lp;            /* current line */
  33.         register long   numchars;       /* # of chars in file */
  34.         register int    numlines;       /* # of lines in file */
  35.         register long   predchars;      /* # chars preceding point */
  36.         register int    predlines;      /* # lines preceding point */
  37.         register int    curchar;        /* character under cursor */
  38.         int ratio;
  39.         int col;
  40.         int savepos;                    /* temp save for current offset */
  41.         int ecol;                       /* column pos/end of current line */
  42.  
  43.         /* starting at the beginning of the buffer */
  44.         lp = curbp->b_linep->l_fp;
  45.         curchar = '\r';
  46.  
  47.         /* start counting chars and lines */
  48.         numchars = 0;
  49.         numlines = 0;
  50.         while (lp != curbp->b_linep) {
  51.                 /* if we are on the current line, record it */
  52.                 if (lp == curwp->w_dotp) {
  53.                         predlines = numlines;
  54.                         predchars = numchars + curwp->w_doto;
  55.                         if ((curwp->w_doto) == llength(lp))
  56.                                 curchar = '\r';
  57.                         else
  58.                                 curchar = lgetc(lp, curwp->w_doto);
  59.                 }
  60.                 /* on to the next line */
  61.                 ++numlines;
  62.                 numchars += llength(lp) + 1;
  63.                 lp = lp->l_fp;
  64.         }
  65.  
  66.         /* if at end of file, record it */
  67.         if (curwp->w_dotp == curbp->b_linep) {
  68.                 predlines = numlines;
  69.                 predchars = numchars;
  70.         }
  71.  
  72.         /* Get real column and end-of-line column. */
  73.         col = getccol(FALSE);
  74.         savepos = curwp->w_doto;
  75.         curwp->w_doto = llength(curwp->w_dotp);
  76.         ecol = getccol(FALSE);
  77.         curwp->w_doto = savepos;
  78.  
  79.         ratio = 0;              /* Ratio before dot. */
  80.         if (numchars != 0)
  81.                 ratio = (100L*predchars) / numchars;
  82.  
  83.         /* summarize and report the info */
  84.         mlwrite(TEXT60,
  85. /*              "Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x" */
  86.                 predlines+1, numlines+1, col, ecol,
  87.                 predchars, numchars, ratio, curchar);
  88.         return(TRUE);
  89. }
  90.  
  91. PASCAL NEAR getcline()  /* get the current line number */
  92.  
  93. {
  94.         register LINE   *lp;            /* current line */
  95.         register int    numlines;       /* # of lines before point */
  96.  
  97.         /* starting at the beginning of the buffer */
  98.         lp = curbp->b_linep->l_fp;
  99.  
  100.         /* start counting lines */
  101.         numlines = 0;
  102.         while (lp != curbp->b_linep) {
  103.                 /* if we are on the current line, record it */
  104.                 if (lp == curwp->w_dotp)
  105.                         break;
  106.                 ++numlines;
  107.                 lp = lp->l_fp;
  108.         }
  109.  
  110.         /* and return the resulting count */
  111.         return(numlines + 1);
  112. }
  113.  
  114. /*
  115.  * Return current column.  Stop at first non-blank given TRUE argument.
  116.  */
  117. PASCAL NEAR getccol(bflg)
  118. int bflg;
  119. {
  120.         register int c, i, col;
  121.         col = 0;
  122.         for (i=0; i<curwp->w_doto; ++i) {
  123.                 c = lgetc(curwp->w_dotp, i);
  124.                 if (c!=' ' && c!='\t' && bflg)
  125.                         break;
  126.                 if (c == '\t')
  127.                         col += -(col % tabsize) + (tabsize - 1);
  128.                 else if (c<0x20 || c==0x7F)
  129.                         ++col;
  130.                 ++col;
  131.         }
  132.         return(col);
  133. }
  134.  
  135. /*
  136.  * Set current column.
  137.  */
  138. PASCAL NEAR setccol(pos)
  139.  
  140. int pos;        /* position to set cursor */
  141.  
  142. {
  143.         register int c;         /* character being scanned */
  144.         register int i;         /* index into current line */
  145.         register int col;       /* current cursor column   */
  146.         register int llen;      /* length of line in bytes */
  147.  
  148.         col = 0;
  149.         llen = llength(curwp->w_dotp);
  150.  
  151.         /* scan the line until we are at or past the target column */
  152.         for (i = 0; i < llen; ++i) {
  153.                 /* upon reaching the target, drop out */
  154.                 if (col >= pos)
  155.                         break;
  156.  
  157.                 /* advance one character */
  158.                 c = lgetc(curwp->w_dotp, i);
  159.                 if (c == '\t')
  160.                         col += -(col % tabsize) + (tabsize - 1);
  161.                 else if (c<0x20 || c==0x7F)
  162.                         ++col;
  163.                 ++col;
  164.         }
  165.  
  166.         /* set us at the new position */
  167.         curwp->w_doto = i;
  168.  
  169.         /* and tell weather we made it */
  170.         return(col >= pos);
  171. }
  172.  
  173. /*
  174.  * Twiddle the two characters on either side of dot. If dot is at the end of
  175.  * the line twiddle the two characters before it. Return with an error if dot
  176.  * is at the beginning of line; it seems to be a bit pointless to make this
  177.  * work. This fixes up a very common typo with a single stroke. Normally bound
  178.  * to "C-T". This always works within a line, so "WFEDIT" is good enough.
  179.  * Don't allow fold symbols to be twiddled. MJB: 03-Oct-89.
  180.  */
  181. PASCAL NEAR twiddle(f, n)
  182. {
  183.         register LINE   *dotp;
  184.         register int    doto;
  185.         register int    cl;
  186.         register int    cr;
  187.         register int    i;
  188.  
  189.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  190.                 return(rdonly());       /* we are in read only mode     */
  191.         dotp = curwp->w_dotp;
  192.         doto = curwp->w_doto;
  193.         if (doto==llength(dotp) && --doto<0)
  194.                 return(FALSE);
  195.  
  196.         /* Check for folds. MJB: 03-Oct-89 */
  197.         if ((dotp->l_type == LEOFOLD) || (dotp->l_type == LEOEFOLD))
  198.                 return(FALSE);
  199.         else if (dotp->l_type == LSOFOLD) {
  200.                 if (((i = indx(dotp->l_text, FOLDSYMBOL)) == -1) ||
  201.                     (doto <= (i + strlen(FOLDSYMBOL))))
  202.                         return(FALSE);
  203.         }
  204.         else if (dotp->l_type == LSOEFOLD) {
  205.                 if (((i = indx(dotp->l_text, BEGINFOLD)) == -1) ||
  206.                     (doto <= (i + strlen(BEGINFOLD))))
  207.                         return(FALSE);
  208.         }
  209.  
  210.         cr = lgetc(dotp, doto);
  211.         if (--doto < dotp->l_lmargin)
  212.                 return(FALSE);
  213.         cl = lgetc(dotp, doto);
  214.         lputc(dotp, doto+0, cr);
  215.         lputc(dotp, doto+1, cl);
  216.         lchange(WFEDIT);
  217.         return(TRUE);
  218. }
  219.  
  220. /*
  221.  * Quote the next character, and insert it into the buffer. All the characters
  222.  * are taken literally, including the newline, which does not then have
  223.  * its line splitting meaning. The character is always read, even if it is
  224.  * inserted 0 times, for regularity. Bound to "C-Q"
  225.  */
  226.  
  227. PASCAL NEAR quote(f, n)
  228.  
  229. {
  230.         register int c;
  231.  
  232.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  233.                 return(rdonly());       /* we are in read only mode     */
  234.         c = tgetc();
  235.         if (n < 0)
  236.                 return(FALSE);
  237.         if (n == 0)
  238.                 return(TRUE);
  239.         return(linsert(n, c, TRUE));
  240. }
  241.  
  242. /*
  243.  * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
  244.  * tab into file.  If given argument, n, of zero, change to hard tabs.
  245.  * If n > 1, simulate tab stop every n-characters using spaces. This has to be
  246.  * done in this slightly funny way because the tab (in ASCII) has been turned
  247.  * into "C-I" (in 10 bit code) already. Bound to "C-I".
  248.  */
  249. PASCAL NEAR tab(f, n)
  250. {
  251.         if (n < 0)
  252.                 return(FALSE);
  253.         if (n == 0 || n > 1) {
  254.                 stabsize = n;
  255.                 return(TRUE);
  256.         }
  257.         if (!stabsize)
  258.                 return(linsert(1, '\t', TRUE));
  259.         return(linsert(stabsize - (getccol(FALSE) % stabsize), ' ', TRUE));
  260. }
  261.  
  262. #if     AEDIT
  263. PASCAL NEAR detab(f, n) /* change tabs to spaces */
  264.  
  265. int f,n;        /* default flag and numeric repeat count */
  266.  
  267. {
  268.         register int inc;       /* increment to next line [sgn(n)] */
  269.  
  270.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  271.                 return(rdonly());       /* we are in read only mode     */
  272.  
  273.         if (f == FALSE)
  274.                 n = reglines();
  275.  
  276.         /* loop thru detabbing n lines */
  277.         inc = ((n > 0) ? 1 : -1);
  278.         while (n) {
  279.                 curwp->w_doto = 0;      /* start at the beginning */
  280.  
  281.                 /* detab the entire current line */
  282.                 while (curwp->w_doto < llength(curwp->w_dotp)) {
  283.                         /* if we have a tab */
  284.                         if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t') {
  285.                                 ldelete(1L, FALSE, FALSE, FALSE);
  286. /*                              insspace(TRUE, 8 - (curwp->w_doto & 7));*/
  287.                                 insspace(TRUE, tabsize - (curwp->w_doto % tabsize));
  288.                         }
  289.                         forwchar(FALSE, 1);
  290.                 }
  291.  
  292.                 /* advance/or back to the next line */
  293.                 forwline(TRUE, inc, TRUE);
  294.                 n -= inc;
  295.         }
  296.         curwp->w_doto = 0;      /* to the begining of the line */
  297.         thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  298.         lchange(WFEDIT);        /* yes, we have made at least an edit */
  299.         return(TRUE);
  300. }
  301.  
  302. PASCAL NEAR entab(f, n) /* change spaces to tabs where posible */
  303.  
  304. int f,n;        /* default flag and numeric repeat count */
  305.  
  306. {
  307.         register int inc;       /* increment to next line [sgn(n)] */
  308.         register int fspace;    /* pointer to first space if in a run */
  309.         register int ccol;      /* current cursor column */
  310.         register char cchar;    /* current character */
  311.         register LINE *lp;      /* line loop */
  312.  
  313.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  314.                 return(rdonly());       /* we are in read only mode     */
  315.  
  316.         /* folded buffers cannot be safely entabbed, due to
  317.          * tabs crossing left margines etc. so don't allow it!
  318.          */
  319.         lp = curbp->b_linep->l_fp;
  320.         while (lp != curbp->b_linep) 
  321.                 if (lp->l_type == LNORMAL)
  322.                         lp = lp->l_fp;
  323.                 else {
  324.                         mlwrite(TEXT239);
  325.                         /* "%Cannot entab folded buffers" */
  326.                         return(FALSE);
  327.                 }
  328.  
  329.         if (f == FALSE)
  330.                 n = reglines();
  331.  
  332.         /* loop thru entabbing n lines */
  333.         inc = ((n > 0) ? 1 : -1);
  334.         while (n) {
  335.                 /* detab the entire current line */
  336.                 while (curwp->w_doto < llength(curwp->w_dotp)) {
  337.                         /* if we have a tab */
  338.                         if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t') {
  339.                                 ldelete(1L, FALSE, FALSE, FALSE);
  340. /*                              insspace(TRUE, 8 - (curwp->w_doto & 7));*/
  341.                                 insspace(TRUE, tabsize - (curwp->w_doto % tabsize));
  342.                         }
  343.                         forwchar(FALSE, 1);
  344.                 }
  345.  
  346.                 /* now, entab the resulting spaced line */
  347.                 curwp->w_doto = 0;      /* start at the beginning */
  348.  
  349.                 /* entab the entire current line */
  350.                 fspace = -1;
  351.                 ccol = 0;
  352.                 while (curwp->w_doto < llength(curwp->w_dotp)) {
  353.                         /* see if it is time to compress */
  354.                         if ((fspace >= 0) && (nextab(fspace) <= ccol))
  355.                         {       if (ccol - fspace < 2)
  356.                                         fspace = -1;
  357.                                 else {
  358.                                         backchar(TRUE, ccol - fspace);
  359.                                         ldelete((long)(ccol - fspace), FALSE, 
  360.                                                 FALSE, FALSE);
  361.                                         linsert(1, '\t', FALSE);        
  362.                                         fspace = -1;
  363.                                 }
  364.                         }
  365.                         /* get the current character */
  366.                         cchar = lgetc(curwp->w_dotp, curwp->w_doto);
  367.  
  368.                         switch (cchar) {
  369.                                 case '\t': /* a tab...count em up */
  370.                                         ccol = nextab(ccol);
  371.                                         break;
  372.  
  373.                                 case ' ':  /* a space...compress? */
  374.                                         if (fspace == -1)
  375.                                                 fspace = ccol;
  376.                                         ccol++;
  377.                                         break;
  378.  
  379.                                 default:   /* any other char...just count */
  380.                                         ccol++;
  381.                                         fspace = -1;
  382.                                         break;
  383.                         }
  384.                         forwchar(FALSE, 1);
  385.                 }
  386.  
  387.                 /* advance/or back to the next line */
  388.                 forwline(TRUE, inc, TRUE);
  389.                 n -= inc;
  390.         }
  391.         curwp->w_doto = 0;      /* to the begining of the line */
  392.         thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  393.         lchange(WFEDIT);        /* yes, we have made at least an edit */
  394.         return(TRUE);
  395. }
  396.  
  397. /* trim:        trim trailing whitespace from the point to eol
  398.                 with no arguments, it trims the current region
  399. */
  400.  
  401. PASCAL NEAR trim(f, n)
  402.  
  403. int f,n;        /* default flag and numeric repeat count */
  404.  
  405. {
  406.         register LINE *lp;      /* current line pointer */
  407.         register int offset;    /* original line offset position */
  408.         register int length;    /* current length */
  409.         register int inc;       /* increment to next line [sgn(n)] */
  410.  
  411.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  412.                 return(rdonly());       /* we are in read only mode     */
  413.  
  414.         if (f == FALSE)
  415.                 n = reglines();
  416.  
  417.         /* loop thru trimming n lines */
  418.         inc = ((n > 0) ? 1 : -1);
  419.         while (n) {
  420.                 lp = curwp->w_dotp;             /* find current line text */
  421.                 offset = curwp->w_doto;         /* save original offset */
  422.                 length = lp->l_used;            /* find current length */
  423.  
  424.                 /* trim the current line */
  425.                 while (length > offset) {
  426.                         if (lgetc(lp, length-1) != ' ' &&
  427.                             lgetc(lp, length-1) != '\t')
  428.                                 break;
  429.                         length--;
  430.                 }
  431.                 lp->l_used = length;
  432.  
  433.                 /* advance/or back to the next line */
  434.                 forwline(TRUE, inc, TRUE);
  435.                 n -= inc;
  436.         }
  437.         lchange(WFEDIT);
  438.         thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  439.         return(TRUE);
  440. }
  441. #endif
  442.  
  443. /*
  444.  * Open up some blank space. The basic plan is to insert a bunch of newlines,
  445.  * and then back up over them. Everything is done by the subcommand
  446.  * procerssors. They even handle the looping. Normally this is bound to "C-O".
  447.  */
  448. PASCAL NEAR openline(f, n)
  449. {
  450.         register int    i;
  451.         register int    s;
  452.  
  453.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  454.                 return(rdonly());       /* we are in read only mode     */
  455.         if (n < 0)
  456.                 return(FALSE);
  457.         if (n == 0)
  458.                 return(TRUE);
  459.         i = n;                                  /* Insert newlines.     */
  460.         do {
  461.                 s = lnewline();
  462.         } while (s==TRUE && --i);
  463.         if (s == TRUE)                          /* Then back up overtop */
  464.                 s = backchar(f, n);             /* of them all.         */
  465.         return(s);
  466. }
  467.  
  468. /*
  469.  * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
  470.  * indentation as specified.
  471.  */
  472. PASCAL NEAR newline(f, n)
  473. {
  474.         register int    s;
  475.  
  476.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  477.                 return(rdonly());       /* we are in read only mode     */
  478.         if (n < 0)
  479.                 return(FALSE);
  480.  
  481.         /* if we are in C mode and this is a default <NL> */
  482.         if (n == 1 && (curbp->b_mode & MDCMOD) &&
  483.             curwp->w_dotp != curbp->b_linep)
  484.                 return(cinsert());
  485.  
  486.         /*
  487.          * If a newline was typed, fill column is defined, the argument is non-
  488.          * negative, wrap mode is enabled, and we are now past fill column,
  489.          * and we are not read-only, perform word wrap.
  490.          */
  491.         if ((curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  492.             getccol(FALSE) > fillcol &&
  493.             (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  494.                 execkey(&wraphook, FALSE, 1);
  495.  
  496.         /* insert some lines */
  497.         while (n--) {
  498.                 if ((s=lnewline()) != TRUE)
  499.                         return(s);
  500.         }
  501.         return(TRUE);
  502. }
  503.  
  504. PASCAL NEAR cinsert()   /* insert a newline and indentation for C */
  505.  
  506. {
  507.         register char *cptr;    /* string pointer into text to copy */
  508.         register int i;         /* index into line to copy indent from */
  509.         register int llen;      /* length of line to copy indent from */
  510.         register int bracef;    /* was there a brace at the end of line? */
  511.         register LINE *lp;      /* current line pointer */
  512.         register int offset;
  513.         char ichar[NSTRING];    /* buffer to hold indent of last line */
  514.  
  515.         /* trim the whitespace before the point */
  516.         lp = curwp->w_dotp;
  517.         offset = curwp->w_doto;
  518.         i = offset - curwp->w_dotp->l_lmargin; /* only goto margin */
  519.  
  520.         while ((i-- > 0) &&
  521.                (lgetc(lp, offset - 1) == ' ' ||
  522.                 lgetc(lp, offset - 1) == '\t')) {
  523.                 backdel(FALSE, 1);
  524.                 offset--;
  525.         }
  526.  
  527.         /* check for a brace */
  528.         bracef = ((offset > 0) && (lgetc(lp, offset - 1) == '{'));
  529.  
  530.         /* put in the newline */
  531.         if (lnewline() == FALSE)
  532.                 return(FALSE);
  533.  
  534.         /* if the new line is not blank... don't indent it! */
  535.         lp = curwp->w_dotp;
  536.         if ((lp->l_used != 0) && (lp->l_used != lp->l_lmargin))
  537.                 return(TRUE);
  538.  
  539.         /* hunt for the last non-blank line to get indentation from */
  540.         while (((lp->l_used == 0) || (lp->l_used == lp->l_lmargin)) &&
  541.                (lp != curbp->b_linep))
  542.                 lp = lp->l_bp;
  543.  
  544.         /* grab a pointer to text to copy indentation from */
  545.         cptr = &(lp->l_text[lp->l_lmargin]);
  546.  
  547.         llen = lp->l_used;
  548.         i = 0;
  549.  
  550.         /* save the indent of the last non blank line */
  551.         while ((i < llen) && (cptr[i] == ' ' || cptr[i] == '\t')
  552.                 && (i < NSTRING - 1)) {
  553.                 /* MJB: 02-Mar-90 - following line has 
  554.                  * undefined evaluation order. won't work on PC:-
  555.                  * ichar[i] = cptr[i++];
  556.                  * changed to:-
  557.                  */
  558.                 ichar[i] = cptr[i];
  559.                 i++;
  560.         }
  561.  
  562.         ichar[i] = 0;           /* terminate it */
  563.  
  564.         /* insert this saved indentation */
  565.         linstr(ichar);
  566.  
  567.         /* and one more tab for a brace */
  568.         if (bracef) 
  569.                 tab(FALSE, 1);
  570.  
  571.         return(TRUE);
  572. }
  573.  
  574. #if     NBRACE
  575. PASCAL NEAR insbrace(n, c)      /* insert a brace into the text here...we are in CMODE */
  576.  
  577. int n;  /* repeat count */
  578. int c;  /* brace to insert (always } for now) */
  579.  
  580. {
  581.         register int ch;        /* last character before input */
  582.         register int oc;        /* caractere oppose a c */
  583.         register int i, count;
  584.         register int target;    /* column brace should go after */
  585.         register LINE *oldlp;
  586.         register int  oldoff;
  587.  
  588.         /* if we aren't at the beginning of the line... */
  589.         if ((curwp->w_doto != 0) && 
  590.             (curwp->w_doto != curwp->w_dotp->l_lmargin))
  591.  
  592.         /* scan to see if all space before this is white space */
  593.                 for (i = curwp->w_doto - 1; i >= 0; --i) {
  594.                         ch = lgetc(curwp->w_dotp, i);
  595.                         if (ch != ' ' && ch != '\t')
  596.                                 return(linsert(n, c, TRUE));
  597.                 }
  598.  
  599.         /* chercher le caractere oppose correspondant */
  600.         switch (c) {
  601.                 case '}': oc = '{'; break;
  602.                 case ']': oc = '['; break;
  603.                 case ')': oc = '('; break;
  604.                 default: return(FALSE);
  605.         }
  606.         
  607.         oldlp = curwp->w_dotp;
  608.         oldoff = curwp->w_doto;
  609.         
  610.         count = 1; backchar(FALSE, 1);
  611.         
  612.         while (count > 0) {
  613.                 if (curwp->w_doto == llength(curwp->w_dotp))
  614.                         ch = '\r';
  615.                 else
  616.                         ch = lgetc(curwp->w_dotp, curwp->w_doto);
  617.  
  618.                 if (ch == c)  ++count;
  619.                 if (ch == oc) --count;
  620.                 
  621.                 backchar(FALSE, 1);
  622.                 if (boundry(curwp->w_dotp, curwp->w_doto, REVERSE))
  623.                         break;
  624.         }
  625.         
  626.         if (count != 0) {       /* no match */
  627.                 curwp->w_dotp = oldlp;
  628.                 curwp->w_doto = oldoff;
  629.                 return(linsert(n, c, TRUE));
  630.         }
  631.         
  632.         curwp->w_doto = 0;              /* debut de ligne */
  633.         /* aller au debut de la ligne apres la tabulation */
  634.         while ((ch = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || ch == '\t')
  635.                 forwchar(FALSE, 1);
  636.  
  637.         /* delete back first */
  638.         target = getccol(FALSE);        /* c'est l'indent que l'on doit avoir */
  639.         curwp->w_dotp = oldlp;
  640.         curwp->w_doto = oldoff;
  641.         
  642.         while (target != getccol(FALSE)) {
  643.                 if (target < getccol(FALSE))    /* on doit detruire des caracteres */
  644.                         while (getccol(FALSE) > target)
  645.                                 backdel(FALSE, 1);
  646.                 else {                          /* on doit en inserer */
  647.                         while (target - getccol(FALSE) >= tabsize)
  648.                                 linsert(1,'\t', TRUE);
  649.                         linsert(target - getccol(FALSE), ' ', TRUE);
  650.                 }
  651.         }
  652.  
  653.         /* and insert the required brace(s) */
  654.         return(linsert(n, c, TRUE));
  655. }
  656. #else
  657. PASCAL NEAR insbrace(n, c) /* insert a brace into the text here...we are in CMODE */
  658.  
  659. int n;  /* repeat count */
  660. int c;  /* brace to insert (always { for now) */
  661.  
  662. {
  663.         register int ch;        /* last character before input */
  664.         register int i;
  665.         register int target;    /* column brace should go after */
  666.  
  667.         /* if we are at the beginning of the line, no go */
  668.         if ((curwp->w_doto == 0) && 
  669.             (curwp->w_doto != curwp->w_dotp->l_lmargin))
  670.                 return(linsert(n,c, TRUE));
  671.  
  672.         /* scan to see if all space before this is white space */
  673.         for (i = curwp->w_doto - 1; i >= 0; --i) {
  674.                 ch = lgetc(curwp->w_dotp, i);
  675.                 if (ch != ' ' && ch != '\t')
  676.                         return(linsert(n, c, TRUE));
  677.         }
  678.  
  679.         /* delete back first */
  680.         target = getccol(FALSE);        /* calc where we will delete to */
  681.         target -= 1;
  682.         target -= target % (stabsize == 0 ? tabsize : stabsize);
  683.         while (getccol(FALSE) > target)
  684.                 backdel(FALSE, 1);
  685.  
  686.         /* and insert the required brace(s) */
  687.         return(linsert(n, c, TRUE));
  688. }
  689. #endif
  690.  
  691. PASCAL NEAR inspound()  /* insert a # into the text here...we are in CMODE */
  692.  
  693. {
  694.         register int ch;        /* last character before input */
  695.         register int i;
  696.  
  697.         /* if we are at the beginning of the line, no go */
  698.         if ((curwp->w_doto == 0) ||
  699.             (curwp->w_doto == curwp->w_dotp->l_lmargin))
  700.                 return(linsert(1,'#', TRUE));
  701.  
  702.         /* scan to see if all space before this is white space */
  703.         for (i = curwp->w_doto - 1; i >= 0; --i) {
  704.                 ch = lgetc(curwp->w_dotp, i);
  705.                 if (ch != ' ' && ch != '\t')
  706.                         return(linsert(1, '#', TRUE));
  707.         }
  708.  
  709.         /* delete back first */
  710.         while (getccol(FALSE) > curwp->w_dotp->l_lmargin)
  711.                 backdel(FALSE, 1);
  712.  
  713.         /* and insert the required pound */
  714.         return(linsert(1, '#', TRUE));
  715. }
  716.  
  717. /*
  718.  * Delete blank lines around dot. What this command does depends if dot is
  719.  * sitting on a blank line. If dot is sitting on a blank line, this command
  720.  * deletes all the blank lines above and below the current line. If it is
  721.  * sitting on a non blank line then it deletes all of the blank lines after
  722.  * the line. Normally this command is bound to "C-X C-O". Any argument is
  723.  * ignored.
  724.  */
  725. PASCAL NEAR deblank(f, n)
  726. {
  727.         register LINE   *lp1;
  728.         register LINE   *lp2;
  729.         long nld;
  730.  
  731.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  732.                 return(rdonly());       /* we are in read only mode     */
  733.         lp1 = curwp->w_dotp;
  734.         while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
  735.                 lp1 = lp2;
  736.         lp2 = lp1;
  737.         nld = 0;
  738.         while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
  739.                 ++nld;
  740.         if (nld == 0)
  741.                 return(TRUE);
  742.         curwp->w_dotp = lforw(lp1);
  743.         curwp->w_doto = 0;
  744.         return(ldelete(nld, FALSE, FALSE, FALSE));
  745. }
  746.  
  747. /*
  748.  * Insert a newline, then enough tabs and spaces to duplicate the indenation
  749.  * of the previous line. Tabs are every tabsize characters. Quite simple.
  750.  * Figure out the indentation of the current line. Insert a newline by calling
  751.  * the standard routine. Insert the indentation by inserting the right number
  752.  * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
  753.  * subcomands failed. Normally bound to "C-J".
  754.  */
  755. PASCAL NEAR indent(f, n)
  756. {
  757.         register int    nicol;
  758.         register int    c;
  759.         register int    i;
  760.  
  761.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  762.                 return(rdonly());       /* we are in read only mode     */
  763.         if (n < 0)
  764.                 return(FALSE);
  765.         while (n--) {
  766.                 nicol = 0;
  767.                 for (i = (curwp->w_dotp->l_type == LSOEFOLD) ? 
  768.                                 loffset(curwp->w_dotp) : 
  769.                                 curwp->w_dotp->l_lmargin;
  770.                      i < llength(curwp->w_dotp); 
  771.                      ++i) {
  772.                         c = lgetc(curwp->w_dotp, i);
  773.                         if (c!=' ' && c!='\t')
  774.                                 break;
  775.                         if (c == '\t')
  776.                                 nicol += -(nicol % tabsize) + (tabsize - 1);
  777.                         ++nicol;
  778.                 }
  779.                 if (lnewline() == FALSE
  780.                 || ((i=nicol/tabsize)!=0 && linsert(i, '\t', FALSE)==FALSE)
  781.                 || ((i=nicol%tabsize)!=0 && linsert(i,  ' ', FALSE)==FALSE))
  782.                         return(FALSE);
  783.         }
  784.         return(TRUE);
  785. }
  786.  
  787. /*
  788.  * Delete forward. This is real easy, because the basic delete routine does
  789.  * all of the work. Watches for negative arguments, and does the right thing.
  790.  * If any argument is present, it kills rather than deletes, to prevent loss
  791.  * of text if typed with a big argument. Normally bound to "C-D".
  792.  */
  793. PASCAL NEAR forwdel(f, n)
  794. {
  795.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  796.                 return(rdonly());       /* we are in read only mode     */
  797.         if (n < 0)
  798.                 return(backdel(f, -n));
  799.         if (f != FALSE) {                       /* Really a kill.       */
  800.                 if ((lastflag&CFKILL) == 0)
  801.                         kdelete();
  802.                 thisflag |= CFKILL;
  803.         }
  804.         return(ldelete((long)n, f, FALSE, TRUE));
  805. }
  806.  
  807. /*
  808.  * Delete backwards. This is quite easy too, because it's all done with other
  809.  * functions. Just move the cursor back, and delete forwards. Like delete
  810.  * forward, this actually does a kill if presented with an argument. Bound to
  811.  * both "RUBOUT" and "C-H".
  812.  */
  813. PASCAL NEAR backdel(f, n)
  814. {
  815.         register int    s;
  816.  
  817.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  818.                 return(rdonly());       /* we are in read only mode     */
  819.         if (n < 0)
  820.                 return(forwdel(f, -n));
  821.         if (f != FALSE) {                       /* Really a kill.       */
  822.                 if ((lastflag&CFKILL) == 0)
  823.                         kdelete();
  824.                 thisflag |= CFKILL;
  825.         }
  826.         if ((s=backchar(f, n)) == TRUE)
  827.                 s = ldelete((long)n, f, FALSE, TRUE);
  828.         return(s);
  829. }
  830.  
  831. /*
  832.  * Kill text. If called without an argument, it kills from dot to the end of
  833.  * the line, unless it is at the end of the line, when it kills the newline.
  834.  * If called with an argument of 0, it kills from the start of the line to dot.
  835.  * If called with a positive argument, it kills from dot forward over that
  836.  * number of newlines. If called with a negative argument it kills backwards
  837.  * that number of newlines. Normally bound to "C-K".
  838.  */
  839. PASCAL NEAR killtext(f, n)
  840. {
  841.         register LINE   *nextp;
  842.         long chunk;
  843.  
  844.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  845.                 return(rdonly());       /* we are in read only mode     */
  846.         if ((lastflag&CFKILL) == 0)             /* Clear kill buffer if */
  847.                 kdelete();                      /* last wasn't a kill.  */
  848.         thisflag |= CFKILL;
  849.         killedcr = TRUE;
  850.         if (curwp->w_doto < curwp->w_dotp->l_lmargin)
  851.                 curwp->w_doto = curwp->w_dotp->l_lmargin;
  852.         if (f == FALSE) {
  853.                 chunk = llength(curwp->w_dotp)-curwp->w_doto;
  854.                 if (chunk == 0)
  855.                         chunk = 1;
  856.                 else killedcr = FALSE;
  857.         } else if (n == 0) {
  858.                 chunk = curwp->w_doto - curwp->w_dotp->l_lmargin;
  859.                 curwp->w_doto = curwp->w_dotp->l_lmargin;
  860.         } else if (n > 0) {
  861.                 chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
  862.                 nextp = lforw(curwp->w_dotp);
  863.                 while (--n) {
  864.                         if (nextp == curbp->b_linep)
  865.                                 return(FALSE);
  866.                         chunk += llength(nextp)+1;
  867.                         nextp = lforw(nextp);
  868.                 }
  869.         } else {
  870.                 mlwrite(TEXT61);
  871. /*                      "%%Negative argumet to kill is illegal" */
  872.                 return(FALSE);
  873.         }
  874.         return(ldelete(chunk, TRUE, FALSE, FALSE));
  875. }
  876.  
  877. PASCAL NEAR setmod(f, n)        /* prompt and set an editor mode */
  878.  
  879. int f, n;       /* default and argument */
  880.  
  881. {
  882.         return(adjustmode(TRUE, FALSE));
  883. }
  884.  
  885. PASCAL NEAR delmode(f, n)       /* prompt and delete an editor mode */
  886.  
  887. int f, n;       /* default and argument */
  888.  
  889. {
  890.         return(adjustmode(FALSE, FALSE));
  891. }
  892.  
  893. PASCAL NEAR setgmode(f, n)      /* prompt and set a global editor mode */
  894.  
  895. int f, n;       /* default and argument */
  896.  
  897. {
  898.         return(adjustmode(TRUE, TRUE));
  899. }
  900.  
  901. PASCAL NEAR delgmode(f, n)      /* prompt and delete a global editor mode */
  902.  
  903. int f, n;       /* default and argument */
  904.  
  905. {
  906.         return(adjustmode(FALSE, TRUE));
  907. }
  908.  
  909. PASCAL NEAR adjustmode(kind, global)    /* change the editor mode status */
  910.  
  911. int kind;       /* true = set,          false = delete */
  912. int global;     /* true = global flag,  false = current buffer flag */
  913. {
  914.         register char *scan;            /* scanning pointer to convert prompt */
  915.         register int i;                 /* loop index */
  916.         register int status;            /* error return on input */
  917. #if     COLOR
  918.         register int uflag;             /* was modename uppercase?      */
  919. #endif
  920.         char prompt[50];        /* string to prompt user with */
  921.         char cbuf[NPAT];                /* buffer to recieve mode name into */
  922.  
  923.         /* build the proper prompt string */
  924.         if (global)
  925.                 strcpy(prompt,TEXT62);
  926. /*                            "Global mode to " */
  927.         else
  928.                 strcpy(prompt,TEXT63);
  929. /*                            "Mode to " */
  930.  
  931.         if (kind == TRUE)
  932.                 strcat(prompt, TEXT64);
  933. /*                             "add: " */
  934.         else
  935.                 strcat(prompt, TEXT65);
  936. /*                             "delete: " */
  937.  
  938.         /* prompt the user and get an answer */
  939.  
  940.         status = mlreply(prompt, cbuf, NPAT - 1);
  941.         if (status != TRUE)
  942.                 return(status);
  943.  
  944.         /* make it uppercase */
  945.  
  946.         scan = cbuf;
  947. #if     COLOR
  948.         uflag = (*scan >= 'A' && *scan <= 'Z');
  949. #endif
  950.         while (*scan)
  951.                 uppercase(scan++);
  952.  
  953.         /* test it first against the colors we know */
  954.         for (i=0; i<NCOLORS; i++) {
  955.                 if (strcmp(cbuf, cname[i]) == 0) {
  956.                         /* finding the match, we set the color */
  957. #if     COLOR
  958.                         if (uflag)
  959.                                 if (global)
  960.                                         gfcolor = i;
  961.                                 else
  962.                                         curwp->w_fcolor = i;
  963.                         else
  964.                                 if (global)
  965.                                         gbcolor = i;
  966.                                 else
  967.                                         curwp->w_bcolor = i;
  968.  
  969.                         curwp->w_flag |= WFCOLR;
  970. #endif
  971.                         mlerase();
  972.                         return(TRUE);
  973.                 }
  974.         }
  975.  
  976.         /* test it against the modes we know */
  977.  
  978.         for (i=0; i < NUMMODES; i++) {
  979.                 if (strcmp(cbuf, modename[i]) == 0) {
  980.                         /* finding a match, we process it */
  981.                         if (kind == TRUE)
  982.                                 if (global)
  983.                                         gmode |= (1 << i);
  984.                                 else
  985.                                         curbp->b_mode |= (1 << i);
  986.                         else
  987.                                 if (global)
  988.                                         gmode &= ~(1 << i);
  989.                                 else
  990.                                         curbp->b_mode &= ~(1 << i);
  991.                         /* display new mode line */
  992.                         if (global == 0)
  993.                                 upmode();
  994.                         mlerase();      /* erase the junk */
  995.                         return(TRUE);
  996.                 }
  997.         }
  998.  
  999.         mlwrite(TEXT66);
  1000. /*              "No such mode!" */
  1001.         return(FALSE);
  1002. }
  1003.  
  1004. /*      This function simply clears the message line,
  1005.                 mainly for macro usage                  */
  1006.  
  1007. PASCAL NEAR clrmes(f, n)
  1008.  
  1009. int f, n;       /* arguments ignored */
  1010.  
  1011. {
  1012.         mlforce("");
  1013.         return(TRUE);
  1014. }
  1015.  
  1016. /*      This function writes a string on the message line
  1017.                 mainly for macro usage                  */
  1018.  
  1019. PASCAL NEAR writemsg(f, n)
  1020.  
  1021. int f, n;       /* arguments ignored */
  1022.  
  1023. {
  1024.         register int status;
  1025.         char buf[NPAT];         /* buffer to recieve message into */
  1026.  
  1027.         if ((status = mlreply(TEXT67, buf, NPAT - 1)) != TRUE)
  1028. /*                            "Message to write: " */
  1029.                 return(status);
  1030.  
  1031.         /* expand all '%' to "%%" so mlwrite won't expect arguments */
  1032.         makelit(buf);
  1033.  
  1034.         /* write the message out */
  1035.         mlforce(buf);
  1036.         return(TRUE);
  1037. }
  1038.  
  1039. #if     CFENCE
  1040. /*      the cursor is moved to a matching fence */
  1041.  
  1042. PASCAL NEAR getfence(f, n)
  1043.  
  1044. int f, n;       /* not used */
  1045.  
  1046. {
  1047.         register LINE *oldlp;   /* original line pointer */
  1048.         register int oldoff;    /* and offset */
  1049.         register int sdir;      /* direction of search (1/-1) */
  1050.         register int count;     /* current fence level count */
  1051.         register char ch;       /* fence type to match against */
  1052.         register char ofence;   /* open fence */
  1053.         register char c;        /* current character in scan */
  1054.  
  1055.         /* save the original cursor position */
  1056.         oldlp = curwp->w_dotp;
  1057.         oldoff = curwp->w_doto;
  1058.  
  1059.         /* get the current character */
  1060.         if (oldoff == llength(oldlp))
  1061.                 ch = '\r';
  1062.         else
  1063.                 ch = lgetc(oldlp, oldoff);
  1064.  
  1065.         /* setup proper matching fence */
  1066.         switch (ch) {
  1067.                 case '(': ofence = ')'; sdir = FORWARD; break;
  1068.                 case '{': ofence = '}'; sdir = FORWARD; break;
  1069.                 case '[': ofence = ']'; sdir = FORWARD; break;
  1070.                 case ')': ofence = '('; sdir = REVERSE; break;
  1071.                 case '}': ofence = '{'; sdir = REVERSE; break;
  1072.                 case ']': ofence = '['; sdir = REVERSE; break;
  1073.                 default: TTbeep(); return(FALSE);
  1074.         }
  1075.  
  1076.         /* set up for scan */
  1077.         count = 1;
  1078.         if (sdir == REVERSE)
  1079.                 backchar(FALSE, 1);
  1080.         else
  1081.                 forwchar(FALSE, 1);
  1082.  
  1083.         /* scan until we find it, or reach the end of file */
  1084.         while (count > 0) {
  1085.                 if (curwp->w_doto == llength(curwp->w_dotp))
  1086.                         c = '\r';
  1087.                 else
  1088.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  1089.                 if (c == ch)
  1090.                         ++count;
  1091.                 if (c == ofence)
  1092.                         --count;
  1093.                 if (sdir == FORWARD)
  1094.                         forwchar(FALSE, 1);
  1095.                 else
  1096.                         backchar(FALSE, 1);
  1097.                 if (boundry(curwp->w_dotp, curwp->w_doto, sdir))
  1098.                         break;
  1099.         }
  1100.  
  1101.         /* if count is zero, we have a match, move the sucker */
  1102.         if (count == 0) {
  1103.                 if (sdir == FORWARD)
  1104.                         backchar(FALSE, 1);
  1105.                 else
  1106.                         forwchar(FALSE, 1);
  1107.                 curwp->w_flag |= WFMOVE;
  1108.                 return(TRUE);
  1109.         }
  1110.  
  1111.         /* restore the current position */
  1112.         curwp->w_dotp = oldlp;
  1113.         curwp->w_doto = oldoff;
  1114.         TTbeep();
  1115.         return(FALSE);
  1116. }
  1117. #endif
  1118.  
  1119. /*      Close fences are matched against their partners, and if
  1120.         on screen the cursor briefly lights there               */
  1121.  
  1122. PASCAL NEAR fmatch(ch)
  1123.  
  1124. char ch;        /* fence type to match against */
  1125.  
  1126. {
  1127.         register LINE *oldlp;   /* original line pointer */
  1128.         register int oldoff;    /* and offset */
  1129.         register LINE *toplp;   /* top line in current window */
  1130.         register int count;     /* current fence level count */
  1131.         register char opench;   /* open fence */
  1132.         register char c;        /* current character in scan */
  1133.         register int i;
  1134.  
  1135.         /* first get the display update out there */
  1136.         update(FALSE);
  1137.  
  1138.         /* save the original cursor position */
  1139.         oldlp = curwp->w_dotp;
  1140.         oldoff = curwp->w_doto;
  1141.  
  1142.         /* setup proper open fence for passed close fence */
  1143.         if (ch == ')')
  1144.                 opench = '(';
  1145.         else if (ch == '}')
  1146.                 opench = '{';
  1147.         else
  1148.                 opench = '[';
  1149.  
  1150.         /* find the top line and set up for scan */
  1151.         toplp = curwp->w_linep->l_bp;
  1152.         count = 1;
  1153.         backchar(FALSE, 2);
  1154.  
  1155.         /* scan back until we find it, or reach past the top of the window */
  1156.         while (count > 0 && curwp->w_dotp != toplp) {
  1157.                 if (curwp->w_doto == llength(curwp->w_dotp))
  1158.                         c = '\r';
  1159.                 else
  1160.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  1161.                 if (c == ch)
  1162.                         ++count;
  1163.                 if (c == opench)
  1164.                         --count;
  1165.                 backchar(FALSE, 1);
  1166.                 if (curwp->w_dotp == curwp->w_bufp->b_linep->l_fp &&
  1167.                     curwp->w_doto == 0)
  1168.                         break;
  1169.         }
  1170.  
  1171.         /* if count is zero, we have a match, display the sucker */
  1172.         /* there is a real machine dependant timing problem here we have
  1173.            yet to solve......... */
  1174.         if (count == 0) {
  1175.                 forwchar(FALSE, 1);
  1176.                 for (i = 0; i < term.t_pause; i++)
  1177.                         update(FALSE);
  1178.         }
  1179.  
  1180.         /* restore the current position */
  1181.         curwp->w_dotp = oldlp;
  1182.         curwp->w_doto = oldoff;
  1183.         return(TRUE);
  1184. }
  1185.  
  1186. PASCAL NEAR istring(f, n)       /* ask for and insert a string into the current
  1187.                    buffer at the current point */
  1188.  
  1189. int f, n;       /* ignored arguments */
  1190.  
  1191. {
  1192.         register int status;    /* status return code */
  1193.         char tstring[NPAT+1];   /* string to add */
  1194.  
  1195.         /* ask for string to insert */
  1196.         status = mltreply(TEXT68, tstring, NPAT, sterm);
  1197. /*                        "String to insert<META>: " */
  1198.         if (status != TRUE)
  1199.                 return(status);
  1200.  
  1201.         if (f == FALSE)
  1202.                 n = 1;
  1203.  
  1204.         if (n < 0)
  1205.                 n = - n;
  1206.  
  1207.         /* insert it */
  1208.         while (n-- && (status = linstr(tstring)))
  1209.                 ;
  1210.         return(status);
  1211. }
  1212.  
  1213. PASCAL NEAR ovstring(f, n) /* ask for and overwite a string into the current
  1214.                    buffer at the current point */
  1215.  
  1216. int f, n;       /* ignored arguments */
  1217.  
  1218. {
  1219.         register int status;    /* status return code */
  1220.         char tstring[NPAT+1];   /* string to add */
  1221.  
  1222.         /* ask for string to insert */
  1223.         status = mltreply(TEXT69, tstring, NPAT, sterm);
  1224. /*                        "String to overwrite<META>: " */
  1225.         if (status != TRUE)
  1226.                 return(status);
  1227.  
  1228.         if (f == FALSE)
  1229.                 n = 1;
  1230.  
  1231.         if (n < 0)
  1232.                 n = - n;
  1233.  
  1234.         /* insert it */
  1235.         while (n-- && (status = lover(tstring)))
  1236.                 ;
  1237.         return(status);
  1238. }
  1239.  
  1240.